package com.vframework.system.permission.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vframework.base.service.impl.BaseServiceImpl;
import com.vframework.system.permission.entity.SysPermission;
import com.vframework.system.permission.mapper.SysPermissionMapper;
import com.vframework.system.permission.service.SysPermissionService;
import com.vframework.system.role.mapper.SysRoleMapper;
import com.vframework.system.token.service.TokenService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author codeGenerator
 * @since 2022-10-28
 */
@Service
public class SysPermissionServiceImpl extends BaseServiceImpl<SysPermissionMapper, SysPermission> implements SysPermissionService {

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Autowired
    private SysPermissionMapper sysPermissionMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    /*@Autowired
    private SysRolePermissionService sysRolePermissionService;*/

    @Autowired
    private TokenService tokenService;

    @Override
    public void sync() throws ClassNotFoundException {
        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
        Map<String, SysPermission> permissionMap = new HashMap<>();
        A:
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
            if (!m.getKey().getPatternsCondition().getPatterns().toString().startsWith("[/admin")) {
                continue;
            }
            RequestMappingInfo info = m.getKey();
            HandlerMethod method = m.getValue();
            // 类名
            String targetName = method.getMethod().getDeclaringClass().getName();
            SysPermission sysPermission = permissionMap.get(targetName);
            Class clazz = Class.forName(targetName);
            if (sysPermission == null) {
                Annotation c = clazz.getAnnotation(Api.class);
//                String r = c == null ? null : ((ActionRemark) c).value();
                String r = c == null ? null : ((Api) c).tags()[0];
                sysPermission = new SysPermission();
                sysPermission.setName(r);
                sysPermission.setChildred(new ArrayList<>());
                sysPermission.setController(targetName);

            }
            SysPermission permission = new SysPermission();
            // 方法名
            String methodName = method.getMethod().getName();
            permission.setMethod(methodName);
            PatternsRequestCondition p = info.getPatternsCondition();
            for (String url : p.getPatterns()) {
                permission.setUrl(url);
            }
            permission.setController(targetName);
            //得到方法
            Method[] methods = clazz.getMethods();
            B:
            for (Method md : methods) {
                if (methodName.equals(md.getName())) {
                    //权限
                    Annotation a = md.getAnnotation(PreAuthorize.class);
                    //名称
//                    Annotation b = md.getAnnotation(ActionRemark.class);
                    Annotation b = md.getAnnotation(ApiOperation.class);
                    String pm = a == null ? null : ((PreAuthorize) a).value();
//                    String remark = b == null ? null : ((ActionRemark) b).value();
                    String remark = b == null ? null : ((ApiOperation) b).value();
                    if (pm != null) {
                        pm = pm.substring(pm.indexOf("(") + 2, pm.indexOf(")") - 1);
                    }
                    permission.setName(remark);
                    permission.setPermission(pm);
                    break B;
                }
            }
            sysPermission.getChildred().add(permission);
            permissionMap.put(targetName, sysPermission);
//            RequestMethodsRequestCondition methodsCondition = info.getMethodsCondition();
//            String type = methodsCondition.toString();
//            if (type != null && type.startsWith("[") && type.endsWith("]")) {
//                type = type.substring(1, type.length() - 1);
//                // 方法名
//                hashMap.put("type", type);
//            }
        }
        List<SysPermission> permissionList = new ArrayList<>();
        for (Map.Entry<String, SysPermission> entry: permissionMap.entrySet()) {
            permissionList.add(entry.getValue());
        }
        List<SysPermission> existPermission = this.list(new QueryWrapper<>());
        Iterator<SysPermission> it = existPermission.iterator();
        syncDb(permissionList, existPermission, it);
        //删除多余permission
        if (existPermission != null && existPermission.size() > 0) {
            List<Integer> ids = new ArrayList<>();
            for (SysPermission permission : existPermission) {
                if (StrUtil.isBlank(permission.getUrl()) || permission.getUrl().indexOf("admin") >= 0) {
                    ids.add(permission.getId());
                }
            }
            if (ids != null && ids.size() > 0) {
                this.removeByIds(ids);
                this.remove(new QueryWrapper<SysPermission>().in("parent_id", ids));
            }
        }
        //获取当前登录用户
        /*SysUser userDetails = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        userDetails.setPermissions(permissions);
        tokenService.refresh(userDetails);*/
    }

    private void syncDb(List<SysPermission> permissionList, List<SysPermission> exitPermission, Iterator<SysPermission> it) {
        for (SysPermission controller : permissionList) {
            A:
            while (it.hasNext()) {
                SysPermission dbPermission = it.next();
                if (controller.getController().equals(dbPermission.getController())
                        && ((controller.getMethod() == null && dbPermission.getMethod() == null) || (controller.getMethod() != null && controller.getMethod().equals(dbPermission.getMethod())))
                ) {
                    controller.setId(dbPermission.getId())
                            .setParentId(dbPermission.getParentId() != null ? dbPermission.getParentId() : controller.getParentId())
                            .setName(StrUtil.isNotBlank(controller.getName()) ? controller.getName() : dbPermission.getName());
                    it.remove();
                    break A;
                }
            }
            super.saveOrUpdate(controller);
            if (controller.getChildred() != null && controller.getChildred().size() > 0) {
                for (SysPermission method : controller.getChildred()) {
                    method.setParentId(controller.getId());
                }
                syncDb(controller.getChildred(), exitPermission, it);
            }
        }
    }
}
